package com.faner4cloud.yun.common.config;

import cn.hutool.core.util.ArrayUtil;
import com.faner4cloud.yun.common.exception.BizException;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.Arrays;
import java.util.Optional;
import java.util.concurrent.*;

/**
 * @描述 异步任务线程池配置
 * @作者 faner
 * @创建时间 2022/4/20 4:22 PM
 */
@EnableAsync
@Configuration
public class TaskExecutorConfiguration implements AsyncConfigurer {
	/**
	 * 获取当前机器的核数, 不一定准确 请根据实际场景 CPU密集 || IO 密集
	 */
	public static final int cpuNum = Runtime.getRuntime().availableProcessors();

	/**
	 * 线程前缀
	 */
	private static ThreadFactory namedThreadFactory = new ThreadFactoryBuilder()
		.setNameFormat("yun-linked-pool-%s").build();

	@Value("${thread.pool.corePoolSize:}")
	private Optional<Integer> corePoolSize;

	@Value("${thread.pool.maxPoolSize:}")
	private Optional<Integer> maxPoolSize;

	@Value("${thread.pool.queueCapacity:}")
	private Optional<Integer> queueCapacity;

	@Value("${thread.pool.awaitTerminationSeconds:}")
	private Optional<Integer> awaitTerminationSeconds;

	@Override
	@Bean
	public Executor getAsyncExecutor() {
		ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
		// 核心线程大小 默认区 CPU 数量
		taskExecutor.setCorePoolSize(corePoolSize.orElse(cpuNum));
		// 最大线程大小 默认区 CPU * 2 数量
		taskExecutor.setMaxPoolSize(maxPoolSize.orElse(cpuNum * 2));
		// 队列最大容量
		taskExecutor.setQueueCapacity(queueCapacity.orElse(500));
		taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
		taskExecutor.setWaitForTasksToCompleteOnShutdown(true);
		taskExecutor.setAwaitTerminationSeconds(awaitTerminationSeconds.orElse(60));
		taskExecutor.setThreadNamePrefix("Task-Thread-");
		taskExecutor.initialize();
		return taskExecutor;
	}

	/**
	 * 异步执行异常处理
	 */
	@Override
	public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
		return (throwable, method, objects) -> {
			throwable.printStackTrace();
			StringBuilder sb = new StringBuilder();
			sb.append("Exception message - ").append(throwable.getMessage())
				.append(", Method name - ").append(method.getName());
			if (ArrayUtil.isNotEmpty(objects)) {
				sb.append(", Parameter value - ").append(Arrays.toString(objects));
			}
			throw new BizException(sb.toString());
		};
//		return new SimpleAsyncUncaughtExceptionHandler();
	}

	/**
	 * 无等待线程池
	 */
	@Bean
	public ExecutorService sync() {
		return new ThreadPoolExecutor(corePoolSize.orElse(cpuNum), maxPoolSize.orElse(cpuNum * 2) + 1,
			60L, TimeUnit.SECONDS,
			new SynchronousQueue<>(), namedThreadFactory,new ThreadPoolExecutor.CallerRunsPolicy());
	}

	/**
	 * 有等待线程池
	 */
	@Bean
	public ThreadPoolExecutor linked() {
		return new ThreadPoolExecutor(corePoolSize.orElse(cpuNum),
			maxPoolSize.orElse(cpuNum * 2) + 1,
			60L,
			TimeUnit.SECONDS,
			new LinkedBlockingDeque<>(queueCapacity.orElse(1024)),
			namedThreadFactory, new ThreadPoolExecutor.CallerRunsPolicy());
	}
}
